{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Demo version of the [square_limit](../../topics/geometry/square_limit.ipynb) topic notebook in ``examples/topics/geometry``.\n",
    "\n",
    "Most examples work across multiple plotting backends, this example is also available for:\n",
    "* [Bokeh - square_limit](../bokeh/square_limit.ipynb)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import holoviews as hv\n",
    "import numpy as np\n",
    "from matplotlib.path import Path\n",
    "from matplotlib.transforms import Affine2D\n",
    "hv.extension('matplotlib')\n",
    "%output fig='svg'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Declaring data and transforms"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "spline=[(0.0,1.0),(0.08,0.98),(0.22,0.82),(0.29,0.72),(0.29,0.72),(0.3,0.64),(0.29,0.57),(0.3,0.5),\n",
    "(0.3,0.5),(0.34,0.4),(0.43,0.32),(0.5,0.26),(0.5,0.26),(0.58,0.21),(0.66,0.22),(0.76,0.2),(0.76,0.2),\n",
    "(0.82,0.12),(0.94,0.05),(1.0,0.0),(1.0,0.0),(0.9,0.03),(0.81,0.04),(0.76,0.05),(0.76,0.05),(0.69,0.04),\n",
    "(0.62,0.04),(0.55,0.04),(0.55,0.04),(0.49,0.1),(0.4,0.17),(0.35,0.2),(0.35,0.2),(0.29,0.24),(0.19,0.28),\n",
    "(0.14,0.31),(0.14,0.31),(0.09,0.35),(-0.03,0.43),(-0.05,0.72),(-0.05,0.72),(-0.04,0.82),(-0.02,0.95),(0.0,1.0),\n",
    "(0.1,0.85),(0.14,0.82),(0.18,0.78),(0.18,0.75),(0.18,0.75),(0.16,0.74),(0.14,0.73),(0.12,0.73),(0.12,0.73),\n",
    "(0.11,0.77),(0.11,0.81),(0.1,0.85),(0.05,0.82),(0.1,0.8),(0.08,0.74),(0.09,0.7),(0.09,0.7),(0.07,0.68),\n",
    "(0.06,0.66),(0.04,0.67),(0.04,0.67),(0.04,0.73),(0.04,0.81),(0.05,0.82),(0.11,0.7),(0.16,0.56),(0.24,0.39),\n",
    "(0.3,0.34),(0.3,0.34),(0.41,0.22),(0.62,0.16),(0.8,0.08),(0.23,0.8),(0.35,0.8),(0.44,0.78),(0.5,0.75),\n",
    "(0.5,0.75),(0.5,0.67),(0.5,0.59),(0.5,0.51),(0.5,0.51),(0.46,0.47),(0.42,0.43),(0.38,0.39),(0.29,0.71),\n",
    "(0.36,0.74),(0.43,0.73),(0.48,0.69),(0.34,0.61),(0.38,0.66),(0.44,0.64),(0.48,0.63),(0.34,0.51),(0.38,0.56),\n",
    "(0.41,0.58),(0.48,0.57),(0.45,0.42),(0.46,0.4),(0.47,0.39),(0.48,0.39),(0.42,0.39),(0.43,0.36),(0.46,0.32),\n",
    "(0.48,0.33),(0.25,0.26),(0.17,0.17),(0.08,0.09),(0.0,0.01),(0.0,0.01),(-0.08,0.09),(-0.17,0.18),(-0.25,0.26),\n",
    "(-0.25,0.26),(-0.2,0.37),(-0.11,0.47),(-0.03,0.57),(-0.17,0.26),(-0.13,0.34),(-0.08,0.4),(-0.01,0.44),\n",
    "(-0.12,0.21),(-0.07,0.29),(-0.02,0.34),(0.05,0.4),(-0.06,0.14),(-0.03,0.23),(0.03,0.28),(0.1,0.34),(-0.02,0.08),\n",
    "(0.02,0.16),(0.09,0.23),(0.16,0.3)]\n",
    "\n",
    "rotT = Affine2D().rotate_deg(90).translate(1, 0)\n",
    "rot45T = Affine2D().rotate_deg(45).scale(1. / np.sqrt(2.), 1. / np.sqrt(2.)).translate(1 / 2., 1 / 2.)\n",
    "flipT = Affine2D().scale(-1, 1).translate(1, 0)\n",
    "\n",
    "def combine(obj):\n",
    "    \"Collapses overlays of Splines to allow transforms of compositions\"\n",
    "    if not isinstance(obj, hv.Overlay): return obj\n",
    "    return hv.Spline((np.vstack([el.data[0] for el in obj.values()]),\n",
    "                      np.hstack([el.data[1] for el in obj.values()])))\n",
    "    \n",
    "def T(spline, transform):\n",
    "    \"Apply a transform to a spline or overlay of splines\"\n",
    "    spline = combine(spline)        \n",
    "    result = Path(spline.data[0], codes=spline.data[1]).transformed(transform)\n",
    "    return hv.Spline((result.vertices, result.codes))\n",
    "\n",
    "def beside(spline1, spline2, n=1, m=1):\n",
    "    den = float(n + m)\n",
    "    t1 = Affine2D().scale(n / den, 1)\n",
    "    t2 = Affine2D().scale(m / den, 1).translate(n / den, 0)\n",
    "    return combine(T(spline1, t1) * T(spline2, t2))\n",
    "\n",
    "def above(spline1, spline2, n=1, m=1):\n",
    "    den = float(n + m)\n",
    "    t1 = Affine2D().scale(1, n / den).translate(0, m / den)\n",
    "    t2 = Affine2D().scale(1, m / den)\n",
    "    return combine(T(spline1, t1) * T(spline2, t2))\n",
    "\n",
    "def nonet(p, q, r, s, t, u, v, w, x):\n",
    "    return above(beside(p, beside(q, r), 1, 2),\n",
    "                 above(beside(s, beside(t, u), 1, 2),\n",
    "                       beside(v, beside(w, x), 1, 2)), 1, 2)\n",
    "\n",
    "def quartet(p, q, r, s):\n",
    "    return above(beside(p, q), beside(r, s))\n",
    "\n",
    "def side(n,t):\n",
    "    if n == 0: \n",
    "        return hv.Spline(([(np.nan, np.nan)],[1]))\n",
    "    else: \n",
    "        return quartet(side(n-1,t), side(n-1,t), rot(t), t)\n",
    "\n",
    "def corner(n,u,t):\n",
    "    if n == 0:\n",
    "        return hv.Spline(([(np.nan, np.nan)],[1]))\n",
    "    else:\n",
    "        return quartet(corner(n-1,u,t), side(n-1,t), rot(side(n-1,t)), u)\n",
    "    \n",
    "def squarelimit(n,u,t):\n",
    "    return nonet(corner(n,u,t), side(n,t), rot(rot(rot(corner(n,u,t)))),\n",
    "                 rot(side(n,t)), u, rot(rot(rot(side(n,t)))), \n",
    "                 rot(corner(n,u,t)), rot(rot(side(n,t))), rot(rot(corner(n,u,t))))\n",
    "\n",
    "def rot(el):        return T(el,rotT)\n",
    "def rot45(el):      return T(el, rot45T)\n",
    "def flip(el):       return T(el, flipT)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Spline [xaxis=None yaxis=None aspect='equal' bgcolor='white'] (linewidth=0.8)\n",
    "%%output size=250\n",
    "\n",
    "fish = hv.Spline((spline, [1,4,4,4]*34)) # Cubic splines\n",
    "smallfish = flip(rot45(fish))\n",
    "t =  fish *  smallfish * rot(rot(rot(smallfish)))\n",
    "u = smallfish * rot(smallfish) * rot(rot(smallfish)) * rot(rot(rot(smallfish)))\n",
    "squarelimit(3,u,t)"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
